package com.yichen.ycOJ.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yichen.ycOJ.common.ErrorCode;
import com.yichen.ycOJ.exception.BusinessException;
import com.yichen.ycOJ.judge.strategy.JudgeStrategyManager;
import com.yichen.ycOJ.model.dto.judge.JudgeContext;
import com.yichen.ycOJ.model.dto.question.JudgeConfig;
import com.yichen.ycOJ.model.dto.questionSubmit.JudgeInfo;
import com.yichen.ycOJ.model.dto.questionSubmit.QuestionSubmitQueryRequest;
import com.yichen.ycOJ.model.entity.Question;
import com.yichen.ycOJ.model.entity.QuestionSubmit;
import com.yichen.ycOJ.model.entity.User;
import com.yichen.ycOJ.model.enums.QuestionSubmitStatusEnum;
import com.yichen.ycOJ.service.JudgeService;
import com.yichen.ycOJ.service.QuestionService;
import com.yichen.ycOJ.service.QuestionSubmitService;
import com.yichen.ycOJ.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author: yichenwu
 * @Date:2024/6/24 10:15
 */
@Slf4j
@Service
public class JudgeServiceImpl implements JudgeService {
    @Autowired
    private QuestionService questionService;
    @Autowired
    private QuestionSubmitService questionSubmitService;
    @Autowired
    private UserService userService;

    @Value("codesandbox:type:remote")
    private String type;

    /**
     * 判题
     */
    @Override
    public QuestionSubmit doJudge(Long questionId, User loginUser) {
        log.info("doJudge:{}", questionId);
        QuestionSubmit questionSubmit = null;
        try {
            // 3.1 获取题目信息、判题用例等
            Question question = questionService.getById(questionId);
            if (question == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "Question not found");
            }
            String judgeCase = question.getJudgeCase();
            JudgeConfig judgeConfig = JSONUtil.toBean(question.getJudgeConfig(), JudgeConfig.class);

            // 3.2 获取题目提交状态等
            QuestionSubmitQueryRequest questionSubmitQueryRequest = new QuestionSubmitQueryRequest();
            Long userId = loginUser.getId();
            questionSubmitQueryRequest.setUserId(userId);
            questionSubmitQueryRequest.setQuestionId(questionId);
            QueryWrapper<QuestionSubmit> questionSubmitQueryWrapper = new QueryWrapper<>();
            questionSubmitQueryWrapper.eq("userId", userId).eq("questionId", questionId);
            questionSubmit = questionSubmitService.getOne(questionSubmitQueryWrapper);
            if (questionSubmit == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "QuestionSubmit not found");
            }

            String language = questionSubmit.getLanguage();
            String code = questionSubmit.getCode();
            Integer status = questionSubmit.getStatus();
            JudgeInfo judgeInfo = JSONUtil.toBean(questionSubmit.getJudgeInfo(), JudgeInfo.class);

            // 3.3 执行判题策略
            JudgeContext judgeContext = new JudgeContext();
            judgeContext.setStatus(status);
            judgeContext.setType(type);
            judgeContext.setCode(code);
            judgeContext.setLanguage(language);
            judgeContext.setJudgeCase(judgeCase);
            judgeContext.setJudgeInfo(judgeInfo);
            judgeContext.setJudgeConfig(judgeConfig);
            judgeContext.setQuestionSubmitId(questionSubmit.getId());

            List<JudgeInfo> judgeInfoStrategy = JudgeStrategyManager.getJudgeStrategy(judgeContext);

            // 3.4 判题结束，修改判题状态
            status = QuestionSubmitStatusEnum.SUCCEED.getValue();
            boolean update1 = questionSubmitService.update(null, new UpdateWrapper<QuestionSubmit>()
                    .set("status", status)
                    .set("judgeInfo", JSONUtil.toJsonStr(judgeInfoStrategy))
                    .eq("id", questionSubmit.getId()));
            if (!update1) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "修改数据库判题状态信息");
            }
        } catch (BusinessException e) {
            log.error("doJudge: " + e.getMessage());
            if (ObjectUtils.isNotEmpty(questionSubmit.getId())){
                boolean update1 = questionSubmitService.update(null, new UpdateWrapper<QuestionSubmit>()
                        .set("status", QuestionSubmitStatusEnum.FAILED.getValue())
                        .eq("id", questionSubmit.getId()));
                if (!update1) {
                    throw new BusinessException(ErrorCode.OPERATION_ERROR, "修改数据库判题状态信息");
                }
            }
        }
        return questionSubmit;
    }
}
